package com.atguigu.srb.core.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.atguigu.srb.common.exception.Assert;
import com.atguigu.srb.common.result.ResponseEnum;
import com.atguigu.srb.core.enums.LendStatusEnum;
import com.atguigu.srb.core.enums.TransTypeEnum;
import com.atguigu.srb.core.hfb.HfbConst;
import com.atguigu.srb.core.hfb.RequestHelper;
import com.atguigu.srb.core.mapper.*;
import com.atguigu.srb.core.pojo.entity.*;
import com.atguigu.srb.core.pojo.vo.BorrowInfoApprovalVO;
import com.atguigu.srb.core.pojo.vo.BorrowerDetailVO;
import com.atguigu.srb.core.service.BorrowerService;
import com.atguigu.srb.core.service.DictService;
import com.atguigu.srb.core.service.LendService;
import com.atguigu.srb.core.service.TransFlowService;
import com.atguigu.srb.core.util.*;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 标的准备表 服务实现类
 * </p>
 *
 * @author Mr.bilal
 * @since 2023-07-18
 */
@Service
public class LendServiceImpl extends ServiceImpl<LendMapper, Lend> implements LendService {

    @Autowired
    DictService dictService;

    @Autowired
    BorrowerService borrowerService;

    @Resource
    BorrowerMapper borrowerMapper;
    
    @Resource
    LendMapper lendMapper;

    @Resource
    UserAccountMapper userAccountMapper;

    @Resource
    UserInfoMapper userInfoMapper;

    @Autowired
    TransFlowService transFlowService;
    
    @Resource
    LendItemMapper lendItemMapper;

    @Resource
    LendReturnMapper lendReturnMapper;

    @Resource
    LendItemReturnMapper lendItemReturnMapper;

    @Override
    public void createLend(BorrowInfoApprovalVO borrowInfoApprovalVO, BorrowInfo borrowInfo) {
        Lend lend = new Lend();
        String lendNo = LendNoUtils.getLendNo();
        // 唯一标的单号
        lend.setLendNo(lendNo);
        // 平台年服务费用
        lend.setServiceRate(borrowInfoApprovalVO.getServiceRate().divide(new BigDecimal("100")));
        // 借款利息年化率
        lend.setLendYearRate(borrowInfoApprovalVO.getLendYearRate().divide(new BigDecimal("100")));
        //投资期数
        lend.setPeriod(borrowInfo.getPeriod());
        //平台预期收益=总借款额*月服务费率*借款期数
        lend.setExpectAmount(borrowInfo.getAmount()
                .multiply(lend.getServiceRate().divide(new BigDecimal("12"),8,BigDecimal.ROUND_HALF_DOWN))
                .multiply(new BigDecimal(lend.getPeriod())));
        lend.setRealAmount(new BigDecimal("0"));

        lend.setUserId(borrowInfo.getUserId());
        lend.setBorrowInfoId(borrowInfo.getId());
        lend.setTitle(borrowInfoApprovalVO.getTitle());
        lend.setAmount(borrowInfo.getAmount());
        lend.setReturnMethod(borrowInfo.getReturnMethod());
        lend.setLowestAmount(new BigDecimal(100));
        lend.setInvestAmount(new BigDecimal(0));
        lend.setInvestNum(0);
        lend.setPublishDate(LocalDateTime.now());
        //起息日期=平台预计放款时间
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        LocalDate lendStartDate = LocalDate.parse(borrowInfoApprovalVO.getLendStartDate(), dateTimeFormatter);
        lend.setLendStartDate(lendStartDate);
        //结束日期=起息日期+借款期数
        LocalDate lendEndDate = lendStartDate.plusMonths(lend.getPeriod());
        lend.setLendEndDate(lendEndDate);
        //描述
        lend.setLendInfo(borrowInfoApprovalVO.getLendInfo());
        //状态
        lend.setStatus(LendStatusEnum.INVEST_RUN.getStatus());
        //审核时间
        lend.setCheckTime(LocalDateTime.now());
        //审核人
        lend.setCheckAdminId(1L);
        baseMapper.insert(lend);
    }

    @Override
    public List<Lend> getList() {

        List<Lend> lends = baseMapper.selectList(null);
        for (Lend lend : lends) {
            lend.getParam()
                    .put("returnMethod",dictService.getDictNameByDictCodeAndValueId("returnMethod",lend.getReturnMethod()));
            lend.getParam()
                    .put("status",LendStatusEnum.getMsgByStatus(lend.getStatus()));
        }
        return lends;
    }

    @Override
    public Map<String, Object> show(Long lendId) {
        HashMap<String, Object> map = new HashMap<>();

        Lend lend = baseMapper.selectById(lendId);
        lend.getParam().put("returnMethod",dictService.getDictNameByDictCodeAndValueId("returnMethod",lend.getReturnMethod()));
        lend.getParam().put("status",LendStatusEnum.getMsgByStatus(lend.getStatus()));


        Long userId = lend.getUserId();
        QueryWrapper<Borrower> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id",userId);
        Borrower borrower = borrowerMapper.selectOne(wrapper);
        BorrowerDetailVO borrowerDetailVO = borrowerService.show(borrower.getId());

        map.put("lend",lend);
        map.put("borrower",borrowerDetailVO);
        return map;
    }

    @Override
    public void makeLoan(long lendId) {
        Lend lend = baseMapper.selectById(lendId);
        String loanNo = LendNoUtils.getLendNo();//标的编号

        // 调用汇付宝放款接口
        HashMap<String, Object> paramMap = new HashMap<>();
        paramMap.put("agentId", HfbConst.AGENT_ID);
        paramMap.put("agentProjectCode", lend.getLendNo());// 标的单号
        paramMap.put("agentBillNo", loanNo);// 放款单号
        paramMap.put("mchFee", lend.getExpectAmount());//平台预期收益
        paramMap.put("timestamp", RequestHelper.getTimestamp());//获取时间戳
        paramMap.put("sign", RequestHelper.getSign(paramMap));//请求数据获取签名
        JSONObject jsonObject = RequestHelper.sendRequest(paramMap, HfbConst.MAKE_LOAD_URL);
        System.out.println("调用汇付宝放款");

        // 付宝放款接口返回结果
        String resultCode = (String) jsonObject.get("resultCode");//结果编码
        String agentProjectCode = (String) jsonObject.get("agentProjectCode");//放款项目编号
        String agentBillNo = (String) jsonObject.get("agentBillNo");//放款单号
        String voteAmt = (String) jsonObject.get("voteAmt");//放款金额
        String mchFee = (String) jsonObject.get("mchFee");//商户手续费

        // 放款成功更新标的信息
        lend.setStatus(LendStatusEnum.PAY_RUN.getStatus());//状态
        lend.setRealAmount(new BigDecimal(mchFee));//实际收益
        lend.setPaymentTime(LocalDateTime.now());//放款时间
        lendMapper.updateById(lend);
        System.out.println("更新标的信息");
        // 根据汇付宝，更新尚融宝借款人账户信息，生成交易流水
        Assert.isTrue(resultCode.equals("0000"), ResponseEnum.COMMON_ERROR);
        Long borrowerUserId = lend.getUserId();//借款用户id
        UpdateWrapper<UserAccount> borrowerUserAccountUpdateWrapper = new UpdateWrapper<>();
        borrowerUserAccountUpdateWrapper
                .eq("user_id",borrowerUserId)
                .setSql("amount = amount + " + voteAmt + ",freeze_amount=freeze_amount + " + 0);
        userAccountMapper.update(null,borrowerUserAccountUpdateWrapper);

        //记录交易流水
        TransFlow borrowerTransFlow = new TransFlow();
        borrowerTransFlow.setTransNo(loanNo);//交易单号==标的编号
        borrowerTransFlow.setTransTypeName(TransTypeEnum.INVEST_UNLOCK.getTransTypeName());//交易类型名称
        UserInfo borrowerUserInfo = userInfoMapper.selectById(borrowerUserId);//借款人基本信息
        borrowerTransFlow.setUserName(borrowerUserInfo.getName());
        borrowerTransFlow.setTransType(TransTypeEnum.INVEST_UNLOCK.getTransType());
        borrowerTransFlow.setTransAmount(new BigDecimal(voteAmt));
        borrowerTransFlow.setUserId(borrowerUserId);
        borrowerTransFlow.setMemo("放款解锁");
        transFlowService.save(borrowerTransFlow);
        System.out.println("根据汇付宝，更新尚融宝借款人账户信息，生成交易流水");
        //根据汇付宝，更新尚融宝投资人账户信息，生成交易流水
        QueryWrapper<LendItem> lendItemQueryWrapper = new QueryWrapper<>();
        lendItemQueryWrapper.eq("lend_id", lendId);
        List<LendItem> lendItems = lendItemMapper.selectList(lendItemQueryWrapper);
        int i = 0;
        for (LendItem lendItem : lendItems) {
            i++;
            Long investUserId = lendItem.getInvestUserId();//投资用户id
            UpdateWrapper<UserAccount> investUserAccountUpdateWrapper = new UpdateWrapper<>();
            investUserAccountUpdateWrapper
                    .eq("user_id", investUserId)
                    .setSql("amount = amount + " + 0 + ",freeze_amount=freeze_amount + " + lendItem.getInvestAmount().negate());//减投资金额
            userAccountMapper.update(null,investUserAccountUpdateWrapper);

            //记录交易流水
            TransFlow investTransFlow = new TransFlow();
            investTransFlow.setTransNo(loanNo + i);//交易单号
            investTransFlow.setTransTypeName(TransTypeEnum.INVEST_UNLOCK.getTransTypeName());//交易类型名称
            UserInfo investUserInfo = userInfoMapper.selectById(investUserId);
            investTransFlow.setUserName(investUserInfo.getName());
            investTransFlow.setTransType(TransTypeEnum.INVEST_UNLOCK.getTransType());
            investTransFlow.setTransAmount(lendItem.getInvestAmount());
            investTransFlow.setUserId(investUserId);
            investTransFlow.setMemo("放款扣账");
            transFlowService.save(investTransFlow);
            System.out.println("根据汇付宝，更新尚融宝投资人账户信息，生成交易流水");
        }

        // 先根据期数生成借款人的还款计划，再根据还款计划和投标人人数生成投标人的回款计划
        createLendReturnPlan(lend, lendItems);
    }

    /**
     * 借款人还款计划
     * @param lend
     * @param lendItems
     */
    private void createLendReturnPlan(Lend lend, List<LendItem> lendItems) {
        // 根据期数生成还款计划
        Integer period = lend.getPeriod();
        for (int i = 1; i <= period; i++) {
            // 生成第i期的还款计划
            LendReturn lendReturn = new LendReturn();//还款记录表
            lendReturn.setReturnMethod(lend.getReturnMethod());//还款方式
            lendReturn.setStatus(LendStatusEnum.PAY_RUN.getStatus());
            lendReturn.setUserId(lend.getUserId());
            lendReturn.setOverdue(false);//是否逾期
            lendReturn.setOverdueTotal(new BigDecimal("0"));//逾期金额
            lendReturn.setLendId(lend.getId());
            lendReturn.setLendYearRate(lend.getLendYearRate());//年化利率
            lendReturn.setLast(i == lend.getPeriod());//是否最后一次还款
            lendReturn.setCurrentPeriod(i);//当前的期数
            lendReturn.setBaseAmount(getBaseAmount(lend.getId(),lend.getAmount(),i));// 计息本金额
            lendReturn.setBorrowInfoId(lend.getBorrowInfoId());//借款信息id
            lendReturn.setAmount(lend.getAmount());//借款金额
            lendReturn.setFee(new BigDecimal("0"));
            lendReturnMapper.insert(lendReturn);// 生成lend_return_id

            // 生成回款计划，计算本金利息
            BigDecimal currentPrincipal = new BigDecimal("0");
            BigDecimal currentInterest = new BigDecimal("0");

            for (LendItem lendItem : lendItems) {
                Map<String,BigDecimal> currentItemReturnMap = createLendItemReturnPlan(lend, lendItem, lendReturn, i);
                currentPrincipal = currentPrincipal.add(currentItemReturnMap.get("currentPrincipal"));//投资人lendItem在第i期的收到的本金
                currentInterest = currentInterest.add(currentItemReturnMap.get("currentInterest"));// 投资人lendItem在第i期的收到的利息
            }
            // 更新本金利息
            lendReturn.setPrincipal(currentPrincipal);// 本金
            lendReturn.setInterest(currentInterest);// 利息
            lendReturn.setTotal(currentPrincipal.add(currentInterest));// 本金+利息
            lendReturnMapper.updateById(lendReturn);
            System.out.println("生成第"+i+"期"+lend.getUserId()+"的还款计划");
        }
    }

    /**
     * 投资人回款计划
     * @param lend
     * @param lendItem
     * @param lendReturn
     * @param i
     * @return
     */
    private Map<String, BigDecimal> createLendItemReturnPlan(Lend lend, LendItem lendItem, LendReturn lendReturn, int i) {
        Map<String, BigDecimal> currentItemReturnMap = new HashMap<>();
        // 生成投资人的回款计划
        LendItemReturn lendItemReturn = new LendItemReturn();
        lendItemReturn.setStatus(LendStatusEnum.PAY_RUN.getStatus());
        lendItemReturn.setOverdueTotal(new BigDecimal("0"));//逾期金额
        lendItemReturn.setOverdue(false);//是否逾期
        lendItemReturn.setReturnMethod(lend.getReturnMethod());//还款方式
        lendItemReturn.setLendYearRate(lend.getLendYearRate());//年化利率
        lendItemReturn.setLendReturnId(lendReturn.getId());//标的还款id
        lendItemReturn.setLendItemId(lendItem.getId());//标的项id
        lendItemReturn.setLendId(lend.getId());//标的id
        lendItemReturn.setInvestUserId(lendItem.getInvestUserId());//投资用户id
        lendItemReturn.setCurrentPeriod(i);//当前的期数
        lendItemReturn.setFee(new BigDecimal("0"));//手续费
        lendItemReturn.setInvestAmount(lendItem.getInvestAmount());//出借金额

        // 计算投资人的收到的本金，利息
        Integer returnMethod = lend.getReturnMethod();//还款方式
        Map<Integer, BigDecimal> perMonthPrincipal = new HashMap<>();//每月还款本金
        Map<Integer, BigDecimal> perMonthInterest = new HashMap<>();//每月还款利息
        if (returnMethod == 1) {
            perMonthPrincipal = Amount1Helper.getPerMonthPrincipal(lendItem.getInvestAmount(), lend.getLendYearRate(), lend.getPeriod());
            perMonthInterest = Amount1Helper.getPerMonthInterest(lendItem.getInvestAmount(), lend.getLendYearRate(), lend.getPeriod());
        }
        if (returnMethod == 2) {
            perMonthPrincipal = Amount2Helper.getPerMonthPrincipal(lendItem.getInvestAmount(), lend.getLendYearRate(), lend.getPeriod());
            perMonthInterest = Amount2Helper.getPerMonthInterest(lendItem.getInvestAmount(), lend.getLendYearRate(), lend.getPeriod());

        }
        if (returnMethod == 3) {
            perMonthPrincipal = Amount3Helper.getPerMonthPrincipal(lendItem.getInvestAmount(), lend.getLendYearRate(), lend.getPeriod());
            perMonthInterest = Amount3Helper.getPerMonthInterest(lendItem.getInvestAmount(), lend.getLendYearRate(), lend.getPeriod());

        }
        if (returnMethod == 4) {
            perMonthPrincipal = Amount4Helper.getPerMonthPrincipal(lendItem.getInvestAmount(), lend.getLendYearRate(), lend.getPeriod());
            perMonthInterest = Amount4Helper.getPerMonthInterest(lendItem.getInvestAmount(), lend.getLendYearRate(), lend.getPeriod());

        }
        BigDecimal currentMonthPrincipal = perMonthPrincipal.get(i);//每月还款本金
        BigDecimal currentMonthInterest = perMonthInterest.get(i);//每月还款利息
        currentItemReturnMap.put("currentInterest",currentMonthInterest);
        currentItemReturnMap.put("currentPrincipal",currentMonthPrincipal);
        lendItemReturn.setPrincipal(currentMonthPrincipal);// 投资人lendItem在第i期的收到的本金
        lendItemReturn.setInterest(currentMonthInterest);// 投资人lendItem在第i期的收到的利息
        lendItemReturn.setTotal(currentMonthPrincipal.add(currentMonthInterest));//本息
        lendItemReturnMapper.insert(lendItemReturn);
        System.out.println("生成第"+i+"期,投资人"+lendItem.getInvestName()+"的回款计划");
        return currentItemReturnMap;
    }

    /**
     * 计息本金
     * @param id 标的id
     * @param baseAmount 标的金额
     * @param i 当前的期数
     * @return
     */
    private BigDecimal getBaseAmount(Long id, BigDecimal baseAmount,int i) {
        QueryWrapper<LendReturn> lendReturnQueryWrapper = new QueryWrapper<>();
        lendReturnQueryWrapper.eq("lend_id",id);//标的id
        lendReturnQueryWrapper.lt("current_period",i);//当前的期数
        List<LendReturn> lendReturns = lendReturnMapper.selectList(lendReturnQueryWrapper);
        if(null!=lendReturns&&lendReturns.size()>0){
            for (LendReturn lendReturn : lendReturns) {
                baseAmount = baseAmount.subtract(lendReturn.getPrincipal());// 本金
            }
        }
        return baseAmount;
    }
}
